package tagdb.ui;


import com.compomics.util.examples.BareBonesBrowserLaunch;
import com.compomics.util.experiment.biology.AminoAcid;
import com.compomics.util.experiment.biology.PTM;
import com.compomics.util.experiment.biology.PTMFactory;
import com.compomics.util.gui.ptm.PtmDialog;
import com.compomics.util.gui.ptm.PtmDialogParent;
import com.compomics.util.pride.CvTerm;
import com.compomics.util.pride.PrideObjectsFactory;
import com.compomics.util.pride.PtmToPrideMap;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import no.uib.jsparklines.extra.HtmlLinksRenderer;
import no.uib.jsparklines.renderers.JSparklinesBarChartTableCellRenderer;
import no.uib.jsparklines.renderers.JSparklinesIntegerColorTableCellRenderer;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.JXTitledPanel;
import org.jfree.chart.plot.PlotOrientation;
import tagdb.io.ModificationFile;
import tagdb.ui.util.PanelFactory;
import tagdb.ui.util.TableConfig;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;

public class ModsDialog extends JDialog implements PtmDialogParent {
    /**
     * The parent main frame.
     */
    private MainFrame mainFrame;
    /**
     * The cell contraints.
     */
    private CellConstraints cc;
    /**
     * The default modifications scroll pane
     */
    private JScrollPane defaultModsScp;
    /**
     * The default modifications table.
     */
    private JXTable defaultModsTbl;
    /**
     * The user modifications scroll pane.
     */
    private JScrollPane userModsScp;

    /**
     * The user modifications table.
     */
    private JXTable userModsTbl;

    /**
     * The post translational modifications factory.
     */
    private PTMFactory ptmFactory = PTMFactory.getInstance();
    /**
     * The PSI-MOD mappings.
     */
    private PtmToPrideMap psiModMap;
    /**
     * The color to use for the HTML tags for the selected rows, in HTML color
     * code.
     */
    private String selectedRowHtmlTagFontColor = "#FFFFFF";
    /**
     * The color used for the sparkline bar chart plots.
     */
    private Color sparklineColor = new Color(110, 196, 97);
    /**
     * The color to use for the HTML tags for the rows that are not selected, in
     * HTML color code.
     */
    private String notSelectedRowHtmlTagFontColor = "#0101DF";
    private ArrayList<String> defaultModsTableToolTips;
    private ArrayList<String> userModsTableToolTips;
    private JButton deleteUserModBtn;
    private JButton addUserModBtn;
    private JButton editUserModBtn;
    private JButton closeBtn;

    /**
     * Constructs the ModsDialog
     *
     * @param mainFrame
     */
    public ModsDialog(MainFrame mainFrame) {
        this.mainFrame = mainFrame;
        initComponents();
        setModal(true);

        // get the psi-mod mappings
        try {
            PrideObjectsFactory prideObjectsFactory = PrideObjectsFactory.getInstance();
            psiModMap = prideObjectsFactory.getPtmToPrideMap();
        } catch (Exception e) {
            e.printStackTrace();
        }
        loadModifications();
    }

    /**
     * Loads the modifications.
     */
    private void loadModifications() {
        //TODO: loadModificationUse(searchGuiParent.loadModificationsUse());
        //updateModificationList();
    }

    /**
     * Initialize the components.
     */
    private void initComponents() {
        // Set dialog title
        setTitle("Configure Modifications");

        ImageIcon modIcon = new ImageIcon(getClass().getResource("/icons/ptm.png"));
        //TODO: this.setIconImage(modIcon);
        // Cell constraints.
        cc = new CellConstraints();
        this.setLayout(new FormLayout("5dlu, p:g, 5dlu", "5dlu, t:p:g, 5dlu, t:p:g, 5dlu, t:p"));

        defaultModsScp = new javax.swing.JScrollPane();
        defaultModsTbl = new JXTable() {
            protected JTableHeader createDefaultTableHeader() {
                return new JTableHeader(columnModel) {
                    public String getToolTipText(MouseEvent e) {
                        Point p = e.getPoint();
                        int index = columnModel.getColumnIndexAtX(p.x);
                        int realIndex = columnModel.getColumn(index).getModelIndex();
                        return (String) defaultModsTableToolTips.get(realIndex);
                    }
                };
            }
        };
        defaultModsTbl.setModel(new DefaultModsTableModel());
        defaultModsTbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        defaultModsTbl.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                defaultModificationsTableMouseClicked(evt);
            }

            public void mouseExited(java.awt.event.MouseEvent evt) {
                defaultModificationsTableMouseExited(evt);
            }

            public void mouseReleased(java.awt.event.MouseEvent evt) {
                defaultModificationsTableMouseReleased(evt);
            }
        });
        defaultModsTbl.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseMoved(java.awt.event.MouseEvent evt) {
                defaultModificationsTableMouseMoved(evt);
            }
        });
        defaultModsScp.setViewportView(defaultModsTbl);
        defaultModsScp.setPreferredSize(new Dimension(800, 270));
        JXTitledPanel defaultModsTtlPnl = PanelFactory.createTitledPanel("Default Modifications", defaultModsScp);

        userModsScp = new javax.swing.JScrollPane();
        userModsTbl = new JXTable() {
            protected JTableHeader createDefaultTableHeader() {
                return new JTableHeader(columnModel) {
                    public String getToolTipText(MouseEvent e) {
                        Point p = e.getPoint();
                        int index = columnModel.getColumnIndexAtX(p.x);
                        int realIndex = columnModel.getColumn(index).getModelIndex();
                        return (String) userModsTableToolTips.get(realIndex);
                    }
                };
            }
        };
        userModsTbl.setModel(new UserModsTableModel());
        userModsTbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        userModsTbl.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                userModificationsTableMouseClicked(evt);
            }

            public void mouseExited(java.awt.event.MouseEvent evt) {
                userModificationsTableMouseExited(evt);
            }

            public void mouseReleased(java.awt.event.MouseEvent evt) {
                userModificationsTableMouseReleased(evt);
            }
        });
        userModsTbl.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseMoved(java.awt.event.MouseEvent evt) {
                userModificationsTableMouseMoved(evt);
            }
        });
        userModsScp.setViewportView(userModsTbl);
        userModsScp.setPreferredSize(new Dimension(800, 270));

        addUserModBtn = new JButton();
        addUserModBtn.setText("Add");
        addUserModBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addUserPTMActionPerformed(evt);
            }
        });

        editUserModBtn = new JButton();
        editUserModBtn.setText("Edit");
        editUserModBtn.setEnabled(false);
        editUserModBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editUserPTMActionPerformed(evt);
            }
        });

        deleteUserModBtn = new JButton();
        deleteUserModBtn.setText("Delete");
        deleteUserModBtn.setEnabled(false);
        deleteUserModBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                deleteUserPTMActionPerformed(evt);
            }
        });

        closeBtn = new JButton();
        closeBtn.setText("Close");
        closeBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });

        JPanel bottomPnl = new JPanel(new BorderLayout());
        JPanel buttonPnl = new JPanel(new FormLayout("5dlu, p, 5dlu, p, 5dlu, p, 15dlu, p, 5dlu", "5dlu, p, 5dlu"));
        buttonPnl.add(addUserModBtn, cc.xy(2, 2));
        buttonPnl.add(editUserModBtn, cc.xy(4, 2));
        buttonPnl.add(deleteUserModBtn, cc.xy(6, 2));
        buttonPnl.add(closeBtn, cc.xy(8, 2));
        bottomPnl.add(buttonPnl, BorderLayout.EAST);

        JXTitledPanel userModsTtlPnl = PanelFactory.createTitledPanel("User Modifications", userModsScp);

        setupTables();
        this.add(defaultModsTtlPnl, cc.xy(2, 2));
        this.add(userModsTtlPnl, cc.xy(2, 4));
        this.add(bottomPnl, cc.xy(2, 6));

        pack();
        setLocationRelativeTo(getOwner());
        setResizable(false);
        setVisible(true);
    }

    /**
     * Set up the table properties.
     */
    private void setupTables() {

        defaultModsTbl.setAutoCreateRowSorter(true);
        userModsTbl.setAutoCreateRowSorter(true);

        // make sure that the scroll panes are see-through
        defaultModsScp.getViewport().setOpaque(false);
        userModsScp.getViewport().setOpaque(false);

        defaultModsTbl.getTableHeader().setReorderingAllowed(false);
        userModsTbl.getTableHeader().setReorderingAllowed(false);

        // Selection background
        defaultModsTbl.setSelectionBackground(TableConfig.ROW_SELECTION_BACKGROUND_COLOR);
        userModsTbl.setSelectionBackground(TableConfig.ROW_SELECTION_BACKGROUND_COLOR);

        // Add striping effect
        defaultModsTbl.addHighlighter(TableConfig.getSimpleStriping());
        userModsTbl.addHighlighter(TableConfig.getSimpleStriping());

        // the index column
        defaultModsTbl.getColumn("#").setMaxWidth(40);
        defaultModsTbl.getColumn("#").setMinWidth(40);
        userModsTbl.getColumn("#").setMaxWidth(40);
        userModsTbl.getColumn("#").setMinWidth(40);

        defaultModsTbl.getColumn("Type").setMaxWidth(50);
        defaultModsTbl.getColumn("Type").setMinWidth(50);
        userModsTbl.getColumn("Type").setMaxWidth(50);
        userModsTbl.getColumn("Type").setMinWidth(50);

        defaultModsTbl.getColumn("PSI-MOD").setMaxWidth(100);
        defaultModsTbl.getColumn("PSI-MOD").setMinWidth(100);
        userModsTbl.getColumn("PSI-MOD").setMaxWidth(100);
        userModsTbl.getColumn("PSI-MOD").setMinWidth(100);

        // set up the ptm type color map
        HashMap<Integer, Color> ptmTypeColorMap = ModificationFile.getColorTypeMap();

        // set up the ptm type tooltip map
        HashMap<Integer, String> ptmTypeTooltipMap = new HashMap<Integer, String>();
        ptmTypeTooltipMap.put(PTM.MODMAX, "max number of modification types");
        ptmTypeTooltipMap.put(PTM.MODAA, "Particular Amino Acid(s)");
        ptmTypeTooltipMap.put(PTM.MODC, "Protein C-term");
        ptmTypeTooltipMap.put(PTM.MODCAA, "Protein C-term - Particular Amino Acid(s)");
        ptmTypeTooltipMap.put(PTM.MODCP, "Peptide C-term");
        ptmTypeTooltipMap.put(PTM.MODCPAA, "Peptide C-term - Particular Amino Acid(s)");
        ptmTypeTooltipMap.put(PTM.MODN, "Protein N-term");
        ptmTypeTooltipMap.put(PTM.MODNAA, "Protein N-term - Particular Amino Acid(s)");
        ptmTypeTooltipMap.put(PTM.MODNP, "Peptide N-term");
        ptmTypeTooltipMap.put(PTM.MODNPAA, "Peptide N-term - Particular Amino Acid(s)");

        defaultModsTbl.getColumn("Type").setCellRenderer(new JSparklinesIntegerColorTableCellRenderer(Color.lightGray, ptmTypeColorMap, ptmTypeTooltipMap));
        userModsTbl.getColumn("Type").setCellRenderer(new JSparklinesIntegerColorTableCellRenderer(Color.lightGray, ptmTypeColorMap, ptmTypeTooltipMap));

        defaultModsTbl.getColumn("PSI-MOD").setCellRenderer(new HtmlLinksRenderer(selectedRowHtmlTagFontColor, notSelectedRowHtmlTagFontColor));
        userModsTbl.getColumn("PSI-MOD").setCellRenderer(new HtmlLinksRenderer(selectedRowHtmlTagFontColor, notSelectedRowHtmlTagFontColor));

        updateMassSparklines();

        // set up the table header tooltips
        defaultModsTableToolTips = new ArrayList<String>();
        defaultModsTableToolTips.add(null);
        defaultModsTableToolTips.add("Modification Name");
        defaultModsTableToolTips.add("Modification Mass Change");
        defaultModsTableToolTips.add("Modification Type");
        defaultModsTableToolTips.add("Affected Residues");
        defaultModsTableToolTips.add("PSI-MOD Mapping");

        userModsTableToolTips = new ArrayList<String>();
        userModsTableToolTips.add(null);
        userModsTableToolTips.add("Modification Name");
        userModsTableToolTips.add("Modification Mass Change");
        userModsTableToolTips.add("Modification Type");
        userModsTableToolTips.add("Affected Residues");
        userModsTableToolTips.add("PSI-MOD Mapping");
    }


    /**
     * Table model for the default mods table.
     */
    private class DefaultModsTableModel extends DefaultTableModel {

        @Override
        public int getRowCount() {
            return ptmFactory.getDefaultModifications().size();
        }

        @Override
        public int getColumnCount() {
            return 6;
        }

        @Override
        public String getColumnName(int column) {
            switch (column) {
                case 0:
                    return "#";
                case 1:
                    return "Name";
                case 2:
                    return "Mass";
                case 3:
                    return "Type";
                case 4:
                    return "Residues";
                case 5:
                    return "PSI-MOD";
                default:
                    return "";
            }
        }

        @Override
        public Object getValueAt(int row, int column) {
            String name = ptmFactory.getDefaultModifications().get(row);
            switch (column) {
                case 0:
                    return row + 1;
                case 1:
                    return name;
                case 2:
                    return ptmFactory.getPTM(name).getMass();
                case 3:
                    return ptmFactory.getPTM(name).getType();
                case 4:
                    String residues = "";
                    for (AminoAcid residue : ptmFactory.getPTM(name).getPattern().getAminoAcidsAtTarget()) {
                        if (!residues.equals("")) {
                            residues += ", ";
                        }
                        residues += residue.singleLetterCode;
                    }
                    return residues;
                case 5:
                    CvTerm cvTerm = null;
                    if (psiModMap != null) {
                        cvTerm = psiModMap.getCVTerm(name);
                    }
                    if (cvTerm != null) {
                        return getOlsAccessionLink(cvTerm.getAccession());
                    } else {
                        cvTerm = PtmToPrideMap.getDefaultCVTerm(name);
                    }

                    if (cvTerm != null) {
                        return getOlsAccessionLink(cvTerm.getAccession());
                    }
                default:
                    return "";
            }
        }

        @Override
        public Class getColumnClass(int columnIndex) {
            for (int i = 0; i < getRowCount(); i++) {
                if (getValueAt(i, columnIndex) != null) {
                    return getValueAt(i, columnIndex).getClass();
                }
            }
            return (new Double(0.0)).getClass();
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return false;
        }
    }

    /**
     * Table model for the user mods table.
     */
    private class UserModsTableModel extends DefaultTableModel {

        @Override
        public int getRowCount() {
            return ptmFactory.getUserModifications().size();
        }

        @Override
        public int getColumnCount() {
            return 6;
        }

        @Override
        public String getColumnName(int column) {
            switch (column) {
                case 0:
                    return "#";
                case 1:
                    return "Name";
                case 2:
                    return "Mass";
                case 3:
                    return "Type";
                case 4:
                    return "Residues";
                case 5:
                    return "PSI-MOD";
                default:
                    return "";
            }
        }

        @Override
        public Object getValueAt(int row, int column) {
            String name = ptmFactory.getUserModifications().get(row);
            switch (column) {
                case 0:
                    return row + 1;
                case 1:
                    return name;
                case 2:
                    return ptmFactory.getPTM(name).getMass();
                case 3:
                    return ptmFactory.getPTM(name).getType();
                case 4:
                    String residues = "";
                    for (AminoAcid residue : ptmFactory.getPTM(name).getPattern().getAminoAcidsAtTarget()) {
                        if (!residues.equals("")) {
                            residues += ", ";
                        }
                        residues += residue.singleLetterCode;
                    }
                    return residues;
                case 5:
                    CvTerm cvTerm = null;
                    if (psiModMap != null) {
                        cvTerm = psiModMap.getCVTerm(name);
                    }
                    if (cvTerm != null) {
                        return getOlsAccessionLink(cvTerm.getAccession());
                    } else {
                        cvTerm = PtmToPrideMap.getDefaultCVTerm(name);
                    }

                    if (cvTerm != null) {
                        return getOlsAccessionLink(cvTerm.getAccession());
                    }
                default:
                    return "";
            }
        }

        @Override
        public Class getColumnClass(int columnIndex) {
            for (int i = 0; i < getRowCount(); i++) {
                if (getValueAt(i, columnIndex) != null) {
                    return getValueAt(i, columnIndex).getClass();
                }
            }
            return (new Double(0.0)).getClass();
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return false;
        }
    }

    /**
     * Update the max value of the mass sparklines.
     */
    private void updateMassSparklines() {

        // get the max absolute mass change
        double maxMassChange = 0;

        for (int i = 0; i < defaultModsTbl.getRowCount(); i++) {
            if (Math.abs((Double) defaultModsTbl.getValueAt(i, defaultModsTbl.getColumn("Mass").getModelIndex())) > maxMassChange) {
                maxMassChange = Math.abs((Double) defaultModsTbl.getValueAt(i, defaultModsTbl.getColumn("Mass").getModelIndex()));
            }
        }

        for (int i = 0; i < userModsTbl.getRowCount(); i++) {
            if (Math.abs((Double) userModsTbl.getValueAt(i, userModsTbl.getColumn("Mass").getModelIndex())) > maxMassChange) {
                maxMassChange = Math.abs((Double) userModsTbl.getValueAt(i, userModsTbl.getColumn("Mass").getModelIndex()));
            }
        }

        defaultModsTbl.getColumn("Mass").setCellRenderer(new JSparklinesBarChartTableCellRenderer(PlotOrientation.HORIZONTAL, -maxMassChange, maxMassChange));
        ((JSparklinesBarChartTableCellRenderer) defaultModsTbl.getColumn("Mass").getCellRenderer()).showNumberAndChart(true, 55, new Font("Arial", Font.PLAIN, 12),0);
        userModsTbl.getColumn("Mass").setCellRenderer(new JSparklinesBarChartTableCellRenderer(PlotOrientation.HORIZONTAL, -maxMassChange, maxMassChange));
        ((JSparklinesBarChartTableCellRenderer) userModsTbl.getColumn("Mass").getCellRenderer()).showNumberAndChart(true, 55, new Font("Arial", Font.PLAIN, 12),0);
    }

    /**
     * Returns the protein accession number as a web link to the given PSI-MOD
     * at http://www.ebi.ac.uk/ontology-lookup.
     *
     * @param modAccession the PSI-MOD accession number
     * @return the OLS web link
     */
    public String getOlsAccessionLink(String modAccession) {
        String accessionNumberWithLink = "<html><a href=\"http://www.ebi.ac.uk/ontology-lookup/?termId=" + modAccession + "\""
                + "\"><font color=\"" + selectedRowHtmlTagFontColor + "\">"
                + modAccession + "</font></a></html>";
        return accessionNumberWithLink;
    }

    /**
     * Open the edit dialog if the user double clicks.
     *
     * @param evt
     */
    private void defaultModificationsTableMouseClicked(MouseEvent evt) {
        if (evt.getClickCount() == 2 && defaultModsTbl.getSelectedRow() != -1) {
            String ptmName = (String) defaultModsTbl.getValueAt(defaultModsTbl.getSelectedRow(), defaultModsTbl.getColumn("Name").getModelIndex());
            PTM ptm = ptmFactory.getPTM(ptmName);
            //TODO: new PtmDialog(searchGuiParent.getMainFrame(), this, ptmToPrideMap, ptm, false);
        }
    }


    /**
     * Opens the PSI-MOD link to the OLS.
     *
     * @param evt
     */
    private void defaultModificationsTableMouseReleased(MouseEvent evt) {
        int row = defaultModsTbl.rowAtPoint(evt.getPoint());
        int column = defaultModsTbl.columnAtPoint(evt.getPoint());

        if (row != -1) {
            if (column == 5) {
                // open protein link in web browser
                if (column == defaultModsTbl.getColumn("PSI-MOD").getModelIndex() && evt != null && evt.getButton() == MouseEvent.BUTTON1
                        && ((String) defaultModsTbl.getValueAt(row, column)).lastIndexOf("<html>") != -1) {

                    String link = (String) defaultModsTbl.getValueAt(row, column);
                    link = link.substring(link.indexOf("\"") + 1);
                    link = link.substring(0, link.indexOf("\""));

                    this.setCursor(new Cursor(Cursor.WAIT_CURSOR));
                    BareBonesBrowserLaunch.openURL(link);
                    this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                }
            }
        }
    }

    /**
     * Changes the cursor to a hand cursor if over the PSI-MOD column.
     *
     * @param evt
     */
    private void defaultModificationsTableMouseMoved(MouseEvent evt) {
        int row = defaultModsTbl.rowAtPoint(evt.getPoint());
        int column = defaultModsTbl.columnAtPoint(evt.getPoint());

        if (row != -1) {

            if (column == 5 && defaultModsTbl.getValueAt(row, column) != null) {

                String tempValue = (String) defaultModsTbl.getValueAt(row, column);

                if (tempValue.lastIndexOf("<html>") != -1) {
                    this.setCursor(new Cursor(Cursor.HAND_CURSOR));
                } else {
                    this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                }

            } else {
                this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            }
        }
    }

    /**
     * Changes the cursor back to the default cursor.
     *
     * @param evt
     */
    private void defaultModificationsTableMouseExited(MouseEvent evt) {
        this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
    }

    /**
     * Changes the cursor back to the default cursor.
     *
     * @param evt
     */
    private void userModificationsTableMouseExited(MouseEvent evt) {
        this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
    }

    /**
     * Changes the cursor to a hand cursor if over the PSI-MOD column.
     *
     * @param evt
     */
    private void userModificationsTableMouseMoved(MouseEvent evt) {
        int row = userModsTbl.rowAtPoint(evt.getPoint());
        int column = userModsTbl.columnAtPoint(evt.getPoint());

        if (row != -1) {

            if (column == 5 && userModsTbl.getValueAt(row, column) != null) {

                String tempValue = (String) userModsTbl.getValueAt(row, column);

                if (tempValue.lastIndexOf("<html>") != -1) {
                    this.setCursor(new Cursor(Cursor.HAND_CURSOR));
                } else {
                    this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                }

            } else {
                this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            }
        }
    }

    /**
     * Open the edit dialog if the user double clicks.
     *
     * @param evt
     */
    private void userModificationsTableMouseClicked(MouseEvent evt) {
        if (evt.getClickCount() == 2 && userModsTbl.getSelectedRow() != -1) {
            String ptmName = (String) userModsTbl.getValueAt(userModsTbl.getSelectedRow(), userModsTbl.getColumn("Name").getModelIndex());
            PTM ptm = ptmFactory.getPTM(ptmName);
            // TODO: new PtmDialog(mainFrame, this, psiModMap, ptm, true);
        }
    }

    /**
     * Opens the PSI-MOD link to the OLS. Enable/disables the user ptm and
     * delete buttons.
     *
     * @param evt
     */
    private void userModificationsTableMouseReleased(MouseEvent evt) {
        editUserModBtn.setEnabled(userModsTbl.getSelectedColumnCount() > 0);
        deleteUserModBtn.setEnabled(userModsTbl.getSelectedColumnCount() > 0);

        int row = userModsTbl.rowAtPoint(evt.getPoint());
        int column = userModsTbl.columnAtPoint(evt.getPoint());

        if (row != -1) {
            if (column == 5) {
                // open protein link in web browser
                if (column == userModsTbl.getColumn("PSI-MOD").getModelIndex() && evt != null && evt.getButton() == MouseEvent.BUTTON1
                        && ((String) userModsTbl.getValueAt(row, column)).lastIndexOf("<html>") != -1) {

                    String link = (String) userModsTbl.getValueAt(row, column);
                    link = link.substring(link.indexOf("\"") + 1);
                    link = link.substring(0, link.indexOf("\""));

                    this.setCursor(new java.awt.Cursor(java.awt.Cursor.WAIT_CURSOR));
                    BareBonesBrowserLaunch.openURL(link);
                    this.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
                }
            }
        }
    }

    /**
     * Add a user mod.
     *
     * @param evt
     */
    private void addUserPTMActionPerformed(java.awt.event.ActionEvent evt) {
       new PtmDialog(mainFrame, this, psiModMap, null, true);
    }

    /**
     * Edit a user mod.
     *
     * @param evt
     */
    private void editUserPTMActionPerformed(java.awt.event.ActionEvent evt) {
        int row = userModsTbl.getSelectedRow();
        String ptmName = (String) userModsTbl.getValueAt(row, userModsTbl.getColumn("Name").getModelIndex());
        PTM ptm = ptmFactory.getPTM(ptmName);
        new PtmDialog(mainFrame, this, psiModMap, ptm, true);
    }

    /**
     * Delete a user mod.
     *
     * @param evt
     */
    private void deleteUserPTMActionPerformed(java.awt.event.ActionEvent evt) {
        int row = userModsTbl.getSelectedRow();
        String ptmName = (String) userModsTbl.getValueAt(row, userModsTbl.getColumn("Name").getModelIndex());
        ptmFactory.removeUserPtm(ptmName);
        updateModifications();
    }

    /**
     * Updates the modification tables
     */
    public void updateModifications() {
        DefaultTableModel dm = (DefaultTableModel) defaultModsTbl.getModel();
        dm.fireTableDataChanged();
        dm = (DefaultTableModel) userModsTbl.getModel();
        dm.fireTableDataChanged();
        editUserModBtn.setEnabled(userModsTbl.getSelectedColumnCount() > 0);
        deleteUserModBtn.setEnabled(userModsTbl.getSelectedColumnCount() > 0);
        updateMassSparklines();
        mainFrame.updateModifications();
    }
}
